/**
 *@Time    : 2021/10/14 10:09
 *@Author  : Shuai Jhou
 *@File    : main
 *@Software: GoLand
 * go run main.go -port=8000 -mode=release -config=configs/
 */

package main

import (
	"context"
	"flag"
	"fmt"
	"github.com/gin-gonic/gin"
	"go.zhoushuai.cn/go-programming-tour-book/blog-service/global"
	"go.zhoushuai.cn/go-programming-tour-book/blog-service/internal/model"
	"go.zhoushuai.cn/go-programming-tour-book/blog-service/internal/routers"
	"go.zhoushuai.cn/go-programming-tour-book/blog-service/pkg/logger"
	"go.zhoushuai.cn/go-programming-tour-book/blog-service/pkg/setting"
	"gopkg.in/natefinch/lumberjack.v2"
	"log"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"time"
)

var (
	port         string
	runMode      string
	config       string
	isVersion    bool
	buildTime    string
	buildVersion string
	gitCommitID  string
)

func init() {
	_ = setupFlag()

	err := setupSetting()
	if err != nil {
		log.Fatalf("init.setupSetting err: %v", err)
	}
	err = setupDBEngine()
	if err != nil {
		log.Fatalf("init.setupDBEngine err: %v", err)
	}
	err = setupLogger()
	if err != nil {
		log.Fatalf("init.setupLogger err: %v", err)
	}
}

// @title 博客系统
// @version 1.0
// @description Go 语言编程之旅：一起用 Go 做项目
// @termsOfService https://github.com/go-programming-tour-book
//  go build -ldflags "-X main.buildTime=`date +%Y-%m-%d,%H:%M:%S` -X main.buildVersion=1.0 -X main.gitCommitID=74110"
func main() {
	if isVersion {
		fmt.Printf("Build-Time:\t %s \n", buildTime)
		fmt.Printf("Build-Version:\t %s \n", buildVersion)
		fmt.Printf("Git-Commit-ID:\t %s \n", gitCommitID)
		return
	}
	gin.SetMode(global.ServerSetting.RunMode)
	readTimeout := global.ServerSetting.ReadTimeout
	writeTimeout := global.ServerSetting.WriteTimeout
	endPoint := fmt.Sprintf(":%s", global.ServerSetting.HttpPort)
	maxHeaderBytes := 1 << 20

	router := routers.NewRouter()
	server := &http.Server{
		Addr:           endPoint,
		Handler:        router,
		ReadTimeout:    readTimeout,
		WriteTimeout:   writeTimeout,
		MaxHeaderBytes: maxHeaderBytes,
	}
	log.Printf("[info] start http server listening %s\n", endPoint)
	go func() {
		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatal("s.ListenAndServe err : ", err)
		}
	}()
	// 等待中断信号
	quit := make(chan os.Signal)
	// 接收syscall.SIGINT syscall.SIGTERM信号
	//signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM,syscall.SIGHUP)
	signal.Notify(quit, os.Interrupt)
	<-quit
	log.Println("Shutdown server...")

	// Wait for interrupt signal to gracefully shut down the server with
	// a timeout of 5 seconds.
	// 最大时间控制，通知该服务端它有5s的时间来处理原来的请求
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := server.Shutdown(ctx); err != nil {
		log.Fatal("Server forced to shutdown:", err)
	}
	log.Println("Server exiting...")
}
func setupSetting() error {
	newSetting, err := setting.NewSetting(strings.Split(config, ",")...)
	if err != nil {
		return err
	}
	err = newSetting.ReadSection("Server", &global.ServerSetting)
	if err != nil {
		return err
	}
	err = newSetting.ReadSection("App", &global.AppSetting)
	if err != nil {
		return err
	}
	err = newSetting.ReadSection("Database", &global.DatabaseSetting)
	if err != nil {
		return err
	}
	err = newSetting.ReadSection("JWT", &global.JWTSetting)
	if err != nil {
		return err
	}
	global.JWTSetting.Expire *= time.Second
	global.ServerSetting.ReadTimeout *= time.Second
	global.ServerSetting.WriteTimeout *= time.Second

	if port != "" {
		global.ServerSetting.HttpPort = port
	}
	if runMode != "" {
		global.ServerSetting.RunMode = runMode
	}
	return nil
}
func setupDBEngine() error {
	var err error
	global.DBEngine, err = model.NewDBEngine(global.DatabaseSetting)
	if err != nil {
		return err
	}

	return nil
}
func setupLogger() error {
	global.Logger = logger.NewLogger(&lumberjack.Logger{
		Filename:  global.AppSetting.LogSavePath + "/" + global.AppSetting.LogFileName + global.AppSetting.LogFileExt,
		MaxSize:   600,
		MaxAge:    10,
		LocalTime: true,
	}, "", log.LstdFlags).WithCaller(2)

	return nil
}
func setupFlag() error {
	flag.StringVar(&port, "port", "", "启动端口")
	flag.StringVar(&runMode, "mode", "", "启动模式")
	flag.StringVar(&config, "config", "configs/", "指定要使用的配置文件路径")
	flag.BoolVar(&isVersion, "version", false, "编译信息")
	flag.Parse()
	return nil
}
